#pragma once
// 进程池的小组件
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "Task.hpp"

const static int gnum = 5; // 表示创建子进程的个数

struct EndPoint
{
public:
    EndPoint(int wfd, pid_t pid)
        : wfd_(wfd), pid_(pid)
    {
        name_ = "child: " + std::to_string(pid_);
    }
    ~EndPoint()
    {
    }

public:
    int wfd_;          // 读端文件描述符
    pid_t pid_;        // 子进程的pid
    std::string name_; // 子进程的名称
};

class ProcessPoll
{
public:
    ProcessPoll()
    {
    }

    void Init()
    {
        std::vector<int> fds;
        for (int i = 0; i < gnum; ++i)
        {
            int fd[2];
            if (pipe(fd) == -1)
            {
                std::cout << "pipe error" << std::endl;
                exit(1);
            }
            pid_t pid = fork();
            if (pid == 0)
            {
                // 子进程
                // 先关闭历史的文件描述符，保证每一个管道文件和子进程之间一一对应
                for (auto fd : fds)
                {
                    close(fd);
                }
                //  关闭写端
                close(fd[1]);
                while (true)
                {
                    int command = -1;
                    int n = read(fd[0], &command, sizeof(command));
                    if (n > 0)
                    {
                        ExecuteCommand(command);
                    }
                    else
                    {
                        if (n == 0)
                        {
                            std::cout << "Father told me to quit,OK..." << std::endl;
                            break;
                        }
                        else
                        {
                            std::cout << "read error" << std::endl;
                            break;
                        }
                    }
                }
                close(fd[0]);
                exit(0);
            }
            // 父进程
            close(fd[0]);
            fds.push_back(fd[1]);
            endPoints_.push_back(EndPoint(fd[1], pid));
        }
    }

    void StartTask(int command)
    {
        int n = command % endPoints_.size();
        int fd = endPoints_[n].wfd_;
        write(fd, &command, sizeof(command));
        std::cout << "give " << command << "task to " << endPoints_[n].name_ << std::endl;
    }

    ~ProcessPoll()
    {
        Destroy();
    }

private:
    void ExecuteCommand(int command)
    {
        t[command]();
    }
    void Destroy()
    {
        for (auto ep : endPoints_)
        {
            int fd = ep.wfd_;
            int pid = ep.pid_;
            std::cout << "fd: " << fd << " pid: " << pid << std::endl;
            close(fd);
            waitpid(pid, NULL, 0);
        }
        std::cout << "ProcessPoll destruct" << std::endl;
    }

private:
    std::vector<EndPoint> endPoints_;
    Task t;
};
